/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.frontendproject.zerocode;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.inspur.edp.lcm.metadata.api.entity.FrameWorkTypeEnum;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProperties;
import com.inspur.edp.web.common.JITEngineConstants;
import com.inspur.edp.web.common.io.FileUtility;
import com.inspur.edp.web.common.logger.WebLogger;
import com.inspur.edp.web.common.serialize.SerializeUtility;
import com.inspur.edp.web.frontendproject.zerocode.operation.ZeroCodeManager;
import com.inspur.edp.web.pageflow.metadata.entity.AdaptedPageFlowMetadataEntity;
import io.iec.edp.caf.commons.utils.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 零代码生成、编译
 * @author noah
 */
public class ZeroCodeServiceImpl implements ZeroCodeService {


    /**
     * 解析表单元数据  生成对应的webdev  json文件   生成ts代码依赖
     *
     * @param zeroCodeParameter
     */
    @Override
    public void resolveMetadataAndGenerateSource(ZeroCodeParameter zeroCodeParameter) {
        prepareOperate(zeroCodeParameter);

        ZeroCodeManager.getInstance().saveZeroCodeParameterMetadataIntoJson(zeroCodeParameter);

        ZeroCodeManager.getInstance().generateSource(zeroCodeParameter);
    }

    /**
     * 编译生成后的代码
     *
     * @param zeroCodeParameter
     */
    @Override
    public void build(ZeroCodeParameter zeroCodeParameter) {
        prepareOperate(zeroCodeParameter);

        ZeroCodeManager.getInstance().build(zeroCodeParameter);
    }

    /**
     * 部署编译后的交付物
     *
     * @param zeroCodeParameter
     */
    @Override
    public void deploy(ZeroCodeParameter zeroCodeParameter) {
        prepareOperate(zeroCodeParameter);

        ZeroCodeManager.getInstance().deploy(zeroCodeParameter);
    }

    /**
     * 解析、编译、部署
     *
     * @param zeroCodeParameter
     */
    @Override
    public void resolveBuildAndDeploy(ZeroCodeParameter zeroCodeParameter) {
        prepareOperate(zeroCodeParameter);

        ZeroCodeManager.getInstance().saveZeroCodeParameterMetadataIntoJson(zeroCodeParameter);
        // 生成源代码
        ZeroCodeManager.getInstance().generateSource(zeroCodeParameter);
        // 编译源代码
        ZeroCodeManager.getInstance().build(zeroCodeParameter);
        // 部署源代码
        ZeroCodeManager.getInstance().deploy(zeroCodeParameter);
    }

    @Override
    public void resolveBuild(ZeroCodeParameter zeroCodeParameter) {
        prepareOperate(zeroCodeParameter);
        if(isVueForm(zeroCodeParameter)){
            resolveVueForm(zeroCodeParameter);
            return;
        }
//        if (zeroCodeParameter.xxx) {
        List<ZeroCodeFormParameter> formParameters = zeroCodeParameter.getFormParameters();
        List<ZeroCodeFormParameter> formatsForm = formParameters.stream().filter(form -> !form.getFormFormatList().isEmpty() && !form.isMobile()).collect(Collectors.toList());
        if (formatsForm.isEmpty() || zeroCodeParameter.getStepCompileCount() == 0) {
            ZeroCodeManager.getInstance().saveZeroCodeParameterMetadataIntoJson(zeroCodeParameter);
            // 生成源代码
            ZeroCodeManager.getInstance().generateSource(zeroCodeParameter);
            // 编译源代码
            ZeroCodeManager.getInstance().build(zeroCodeParameter);
            return;
        }

        int stepCompileCount = zeroCodeParameter.getStepCompileCount();
        List<ZeroCodeFormFormatParameter> formFormatListTmp;
        for (int i = 0; i < formatsForm.size(); i++) {
            ZeroCodeFormParameter form = formatsForm.get(i);
            List<ZeroCodeFormFormatParameter> formFormatList = form.getFormFormatList();
            formFormatListTmp = new ArrayList<>(formFormatList);
            if (formFormatListTmp.size() > stepCompileCount) {
                WebLogger.Instance.info("Start loop compilation ");

                int blockSum = (formFormatListTmp.size() + stepCompileCount - 1) / stepCompileCount;
                WebLogger.Instance.info("current " + blockSum + "blocks。");
                // 使用Set来跟踪已经添加的key，以确保唯一性
                Set<String> uniqueKeys = new HashSet<>();
                JSONArray mergedAndDeduplicatedArray = new JSONArray();
                for (int j = 0; j < formFormatListTmp.size(); j += stepCompileCount) {

                    int currentStep = j / stepCompileCount + 1;
                    WebLogger.Instance.info("Start compile" + currentStep + " block。");
                    int endIndex = Math.min(j + stepCompileCount, formFormatListTmp.size());
                    List<ZeroCodeFormFormatParameter> block = formFormatListTmp.subList(j, endIndex);
                    WebLogger.Instance.info("block size " + block.size());
                    formFormatList.clear();
                    formFormatList.addAll(block);
                    zeroCodeParameter.setStepCompileCount(stepCompileCount);
                    zeroCodeParameter.setCurrentCompileStep(currentStep);
                    ZeroCodeManager.getInstance().saveZeroCodeParameterMetadataIntoJson(zeroCodeParameter);
                    ZeroCodeManager.getInstance().generateSource(zeroCodeParameter);
                    // 编译源代码
                    ZeroCodeManager.getInstance().build(zeroCodeParameter);
                    String distRollupPath = FileUtility.getPlatformIndependentPath(
                            FileUtility.combineOptional(
                                    zeroCodeParameter.getAbsoluteBasePath(),
                                    "src",
                                    "app",
                                    JITEngineConstants.DistRollupPathName));
                    String stepCompileDistRollupPath = FileUtility.getPlatformIndependentPath(
                            FileUtility.combineOptional(
                                    zeroCodeParameter.getAbsoluteBasePath(),
                                    "src",
                                    JITEngineConstants.StepCompileDistRollup));
                    String versionJsonPath = FileUtility.combineOptional(distRollupPath, zeroCodeParameter.getProjectName(), "version.json");

                    if (FileUtility.exists(versionJsonPath)) {
                        String versionJson = FileUtility.readAsString(versionJsonPath);
                        if (!StringUtils.isEmpty(versionJson)) {
                            // 解析JSON数组字符串为JSONArray对象
                            JSONArray versionJsonArray = JSONArray.parseArray(versionJson);
                            // 合并并去重
                            mergeAndDeduplicate(versionJsonArray, uniqueKeys, mergedAndDeduplicatedArray);
                        }
                    }
                    if (currentStep < blockSum) {
                        WebLogger.Instance.info("copy " + distRollupPath + " to " + stepCompileDistRollupPath);
                        FileUtility.copyFolder(distRollupPath, stepCompileDistRollupPath);
                    } else {
                        WebLogger.Instance.info("copy " + stepCompileDistRollupPath + " to " + distRollupPath);
                        FileUtility.copyFolder(stepCompileDistRollupPath, distRollupPath);
                        FileUtility.deleteFolder(stepCompileDistRollupPath);
                        FileUtility.writeFile(versionJsonPath, mergedAndDeduplicatedArray.toJSONString());
                    }

                }
            } else {
                ZeroCodeManager.getInstance().saveZeroCodeParameterMetadataIntoJson(zeroCodeParameter);
                // 生成源代码
                ZeroCodeManager.getInstance().generateSource(zeroCodeParameter);
                // 编译源代码
                ZeroCodeManager.getInstance().build(zeroCodeParameter);
            }
        }
    }

    private void resolveVueForm(ZeroCodeParameter zeroCodeParameter) {
        ZeroCodeManager.getInstance().saveZeroCodeParameterMetadataIntoJson(zeroCodeParameter);

    }

    private boolean isVueForm(ZeroCodeParameter zeroCodeParameter) {
        if(zeroCodeParameter.getFormParameters().isEmpty()){
            return false;
        }

        List<ZeroCodeFormParameter> formParameters = zeroCodeParameter.getFormParameters().stream().filter(form -> {
            MetadataProperties properties = form.getMetadata().getProperties();
            return properties != null && properties.getFramework() == FrameWorkTypeEnum.Vue;
        }).collect(Collectors.toList());

        return !formParameters.isEmpty();
    }

    private static void mergeAndDeduplicate(JSONArray jsonArray, Set<String> uniqueKeys, JSONArray mergedArray) {
        if (jsonArray != null) {
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String keyValue = jsonObject.getString("key");
                if (!uniqueKeys.contains(keyValue)) {
                    uniqueKeys.add(keyValue);
                    mergedArray.add(jsonObject);
                }
            }
        }

    }


    @Override
    public Map<String, AdaptedPageFlowMetadataEntity> saveJson(ZeroCodeParameter zeroCodeParameter) {
        prepareOperate(zeroCodeParameter);

        ZeroCodeManager.getInstance().saveZeroCodeParameterMetadataIntoJson(zeroCodeParameter);

        return zeroCodeParameter.getPageFlowMap();
    }

    /**
     * 执行前操作
     * @param zeroCodeParameter
     */
    private  void prepareOperate(ZeroCodeParameter zeroCodeParameter){
        ZeroCodeParameterInitializer.initialize(zeroCodeParameter);
        // 入参验证
        ZeroCodeParameterValidator.validate(zeroCodeParameter);
    }

    @Override
    public void generateSourceAndBuild(ZeroCodeParameter zeroCodeParameter) {
        prepareOperate(zeroCodeParameter);
        Map<String, AdaptedPageFlowMetadataEntity> pageFlowMap = zeroCodeParameter.getPageFlowMap();
        if (pageFlowMap != null) {
            // 遍历pageFlowMap
            for (String key : pageFlowMap.keySet()) {
                FileUtility.writeFile(key, SerializeUtility.getInstance().serialize(pageFlowMap.get(key)));
            }
        }
        // 默认分布编译
        zeroCodeParameter.setStepCompileCount(10);
        ZeroCodeManager.getInstance().generateSource(zeroCodeParameter);

        ZeroCodeManager.getInstance().build(zeroCodeParameter);
    }
}
